package org.jiuling.request.http.core;

import org.jiuling.basics.enums.CharsetEnum;
import org.jiuling.basics.enums.HttpRequestMethodEnum;
import org.jiuling.basics.util.InputStreamUtil;
import org.jiuling.basics.validation.MapVerify;
import org.jiuling.basics.validation.ObjectVerify;
import org.jiuling.basics.validation.StringVerify;
import org.jiuling.request.exception.RequestRuntimeException;
import org.jiuling.request.http.HttpRequest;
import org.jiuling.request.http.enums.SSLProtocolEnum;
import org.jiuling.request.http.model.HttpRequestBody;
import org.jiuling.request.http.model.HttpRequestHeader;
import org.jiuling.request.http.model.HttpRequestParam;
import org.jiuling.request.http.model.HttpResponse;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * Http请求核心
 * @author 紫灵
 * @date 2024年08月23日 22时05分00秒
 */
public abstract class HttpRequestCore implements HttpRequest {

    /** URI */
    private URI uri;
    /** 代理 */
    private Proxy proxy;
    /** 请求方式 */
    protected HttpRequestMethodEnum httpRequestMethod;
    /** 链接超时时间 */
    private int connectTimeout;
    /** 读取超时时间 */
    private int readTimeout;
    /** 请求头 */
    private HttpRequestHeader httpRequestHeader;
    /** 请求参数 */
    private HttpRequestParam httpRequestParam;
    /** 请求内容 */
    private HttpRequestBody httpRequestBody;
    /** ssl协议 */
    protected SSLProtocolEnum sslProtocol;

    public HttpRequestCore(URI uri) {
        this.uri = uri;
        // 默认请求为GET
        this.httpRequestMethod = HttpRequestMethodEnum.GET;
        // 链接超时3000毫秒
        this.connectTimeout = 3000;
        // 读取超时5000毫秒
        this.readTimeout = 5000;
        // 默认ssl协议为SSL
        this.sslProtocol = SSLProtocolEnum.SSL;
    }

    @Override
    public void setConnectTimeout(int connectTimeout) {
        if (connectTimeout <= 0) return;
        this.connectTimeout = connectTimeout;
    }


    @Override
    public void setReadTimeout(int readTimeout) {
        if (readTimeout <= 0) return;
        this.readTimeout = readTimeout;
    }

    @Override
    public void setHttpRequestHeader(HttpRequestHeader httpRequestHeader) {
        if (MapVerify.isBlank(httpRequestHeader)) return;
        this.httpRequestHeader = httpRequestHeader;
    }

    @Override
    public void setHttpRequestParam(HttpRequestParam httpRequestParam) {
        if (MapVerify.isBlank(httpRequestParam)) return;
        StringBuffer urlStringBuffer = new StringBuffer(this.uri.toString());
        if (urlStringBuffer.indexOf("?") >= 0){
            urlStringBuffer.append("&");
        }else {
            urlStringBuffer.append("?");
        }
        httpRequestParam.forEach((k,v)->{
            try {
                urlStringBuffer
                        .append(URLEncoder.encode(k, CharsetEnum.UTF_8.getLowercase()))
                        .append("=")
                        .append(URLEncoder.encode(String.valueOf(v), CharsetEnum.UTF_8.getLowercase()))
                        .append("&");
            } catch (UnsupportedEncodingException e) {
                throw new RequestRuntimeException("URL格式转换异常！");
            }
        });
        // 移除最后一个字符
        urlStringBuffer.deleteCharAt(urlStringBuffer.length()-1);
        try {
            this.uri = new URI(urlStringBuffer.toString());
        } catch (URISyntaxException e) {
            throw new RequestRuntimeException(e.getLocalizedMessage());
        }
        this.httpRequestParam = httpRequestParam;
    }

    @Override
    public void setHttpRequestBody(HttpRequestBody httpRequestBody) {
        if (MapVerify.isBlank(httpRequestBody)) return;
        this.httpRequestBody = httpRequestBody;
    }

    @Override
    public void setSSLProtocol(SSLProtocolEnum sslProtocol) {
        if (ObjectVerify.isNull(sslProtocol)) return;
        this.sslProtocol = sslProtocol;
    }

    /**
     * 开启链接
     * @return URL链接
     */
    protected URLConnection openConnection(){
        try {
            URL url = uri.toURL();
            return ObjectVerify.isNull(proxy)?url.openConnection():url.openConnection(proxy);
        } catch (IOException e) {
            throw new RequestRuntimeException("URL格式错误！");
        }
    }

    @Override
    public void setHttpRequestMethod(HttpRequestMethodEnum httpRequestMethod) {
        this.httpRequestMethod = httpRequestMethod;
    }

    @Override
    public void setProxy(String ip, int port,Proxy.Type proxyType) {
        this.proxy = new Proxy(proxyType, new InetSocketAddress(ip, port));
    }

    /**
     * 链接
     * @param urlConnection url链接
     */
    protected void connect(URLConnection urlConnection){
        urlConnection.setConnectTimeout(connectTimeout);
        urlConnection.setReadTimeout(readTimeout);
        // 设置请求头
        if (!MapVerify.isBlank(httpRequestHeader)){
           httpRequestHeader.forEach(urlConnection::setRequestProperty);
        }
        try {
            if (!httpRequestMethod.equals(HttpRequestMethodEnum.GET) &&
                    !ObjectVerify.isNull(httpRequestBody)){
                // 设置输入实处权限
                urlConnection.setDoInput(true);
                urlConnection.setDoOutput(true);
                OutputStream outputStream = urlConnection.getOutputStream();
                outputStream.write(httpRequestBody.getBody().getBytes(StandardCharsets.UTF_8));
                // 关闭输入流
                outputStream.close();
            }else {
                urlConnection.connect();
            }
        }catch (IOException e){
            throw new RequestRuntimeException("请求失败！");
        }
    }

    protected HttpResponse packageHttpResponse(HttpURLConnection httpURLConnection) throws IOException {
        HttpResponse httpResponse = new HttpResponse();
        httpResponse.setHttpResponseStatus(httpURLConnection.getResponseCode());

        try(InputStream errorInputStream = httpURLConnection.getErrorStream()){
            if(!ObjectVerify.isNull(errorInputStream)){
                httpResponse.setErrorBody(InputStreamUtil.readInputStream(errorInputStream));
                // 读取数据后关闭流
                errorInputStream.close();
            }
        }catch (FileNotFoundException ignored){
            // 不处理该异常
        }

        // 处理数据流信息
        try (InputStream inputStream = httpURLConnection.getInputStream()){
            if(!ObjectVerify.isNull(inputStream)){
                httpResponse.setBody(InputStreamUtil.readInputStream(inputStream));
            }
        }catch (FileNotFoundException ignored){
            // 该异常不处理
        }

        return httpResponse;
    }

}
